﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Collections;
using System.Reflection;

namespace PickGold.Collections
{
	/// <summary>
	/// 固定容量的对象集合
	/// </summary>
	/// <typeparam name="T">集合元素的类型</typeparam>
	public class FixedCollection<T> : IEnumerable<T>, IDisposable
	{
		#region inner class

		private class FixedEnumerator : IEnumerator<T>
		{
			public FixedCollection<T> Data;
			public int Index;

			public FixedEnumerator(FixedCollection<T> data, int index)
			{
				this.Data = data;
				this.Index = data.Index;
			}

			T IEnumerator<T>.Current
			{
				get
				{
					if (this.Data == null)
						throw new ObjectDisposedException(typeof(IEnumerator).Name);

					return this.Data.Items[this.Index % this.Data.Capacity];
				}
			}

			object IEnumerator.Current
			{
				get
				{
					if (this.Data == null)
						throw new ObjectDisposedException(typeof(IEnumerator).Name);

					return this.Data.Items[this.Index % this.Data.Capacity];
				}
			}

			void IDisposable.Dispose()
			{
				this.Data = null;
			}

			bool IEnumerator.MoveNext()
			{
				if (this.Data == null)
					throw new ObjectDisposedException(typeof(IEnumerator).Name);

				this.Index++;
				if (this.Index % this.Data.Capacity == this.Data.Index % this.Data.Capacity)
					return false;

				return true;
			}

			void IEnumerator.Reset()
			{
				this.Index = this.Data.Index;
			}
		}

		#endregion

		/// <summary>
		/// 元素集合
		/// </summary>
		public readonly T[] Items;

		/// <summary>
		/// 内容最大数
		/// </summary>
		public readonly int Capacity;

		/// <summary>
		/// 当前位置
		/// </summary>
		public int Index;

		/// <summary>
		/// 构造一个固定内容对象集合的实例
		/// </summary>
		/// <param name="capacity">容量，不可小于等于零。</param>
		public FixedCollection(int capacity)
		{
			if (capacity <= 0)
				throw new ArgumentOutOfRangeException(MethodBase.GetCurrentMethod().GetParameters()[0].Name);

			this.Index = 0;
			this.Capacity = capacity;
			this.Items = new T[capacity];
		}

		/// <summary>
		/// 取指定位置处的元素对象
		/// </summary>
		/// <param name="index">元素位置</param>
		/// <returns>定位置处的元素对象</returns>
		public T this[int index]
		{
			set
			{
				if (index >= 0)
					index = index % this.Capacity;
				else
					index = (this.Index + this.Capacity + (index % this.Capacity)) % this.Capacity;
				this.Items[index] = value;
			}
			get
			{
				if (index >= 0)
					index = index % this.Capacity;
				else
					index = (this.Index + this.Capacity + (index % this.Capacity)) % this.Capacity;
				return this.Items[index];
			}
		}

		/// <summary>
		/// 上一个对象
		/// </summary>
		public T Last
		{
			set
			{
				this.Items[(this.Index + this.Capacity - 1) % this.Capacity] = value;
			}
			get
			{
				return this.Items[(this.Index + this.Capacity - 1) % this.Capacity];
			}
		}

		/// <summary>
		/// 上一个对象
		/// </summary>
		public T Next
		{
			set
			{
				this.Items[this.Index % this.Capacity] = value;
			}
			get
			{
				return this.Items[this.Index % this.Capacity];
			}
		}

		/// <summary>
		/// 开头设置一个元素并将位置前移
		/// </summary>
		/// <param name="value">要设置的元素</param>
		/// <returns>当前位置</returns>
		public int Push(T value)
		{
			this.Index = this.Index % this.Capacity;
			var v = this.Items[this.Index];
			this.Items[this.Index] = value;
			return ++this.Index % this.Capacity;
		}

		/// <summary>
		/// 末尾设置一个元素并将位置后移
		/// </summary>
		/// <param name="value">要设置的元素</param>
		/// <returns>当前位置</returns>
		public int Queue(T value)
		{
			this.Index = this.Index % this.Capacity;
			var v = this.Items[this.Index];
			this.Items[this.Index] = value;
			if (--this.Index >= 0)
				return this.Index % this.Capacity;

			this.Index = this.Capacity - 1;
			return this.Index;
		}

		/// <summary>
		/// 查找集合是否包含指定的对象
		/// </summary>
		/// <param name="value">要查找的对象</param>
		/// <param name="comparer">对象比较器</param>
		/// <returns>对象所在的位置</returns>
		public int IndexOf(T value, IComparer<T> comparer)
		{
			for (var i = 0; i < this.Capacity; i++)
			{
				if (comparer.Compare(this.Items[i], value) == 0)
					return i;
			}

			return -1;
		}

		/// <summary>
		/// 查找集合是否包含指定的对象
		/// </summary>
		/// <param name="comparer">可比较对象</param>
		/// <returns>对象所在的位置</returns>
		public int IndexOf(IComparable<T> comparer)
		{
			for (var i = 0; i < this.Capacity; i++)
			{
				if (comparer.CompareTo(this.Items[i]) == 0)
					return i;
			}

			return -1;
		}

		/// <summary>
		/// 取枚举器对象
		/// </summary>
		/// <returns>枚举器对象</returns>
		public IEnumerator<T> GetEnumerator()
		{
			return new FixedEnumerator(this, this.Index);
		}

		IEnumerator IEnumerable.GetEnumerator()
		{
			return new FixedEnumerator(this, this.Index);
		}

		/// <summary>
		/// 将集合内所有对象置为默认值
		/// </summary>
		public void Dispose()
		{
			for (var i = 0; i < this.Capacity; i++)
				this.Items[i] = Reflector<T>.DefaultValue;
		}
	}
}
